using System.Collections;
using System.Collections.Generic;
using JufGame.Collections.Generic;
using UnityEngine;

namespace JufGame
{
	public class LOD_Trader : MonoSingleton<LOD_Trader>
	{
		private const float MAX_RESOURCE = 10000f;
		private const float NEAR_ZERO = 1E-8f;
		[Tooltip("剩余可用资源")]
		[SerializeField] private Vector4 availableResources;
		[Tooltip("环境注意程度负载占总注意程度负载的比重，值越高资源越偏向背景角色，反之偏向前景角色")]
		[SerializeField, Range(0, 1)] private float ambMul = 0.333f;
		[SerializeField] private LOD_Character[] characters;
		[Tooltip("所有玩家的视野相机")]
		[SerializeField] private Camera[] viewCameras;
		private MyHeap<SolutionTrans> upgradTrans;
		private MyHeap<SolutionTrans> downgradTrans;
		private MyHeap<LOD_Character> upgradCharacters;
		private MyHeap<LOD_Character> downgradCharacters;
		private List<SolutionTrans> hypTrades;//拟定交易集
		private readonly int maxLoopTime = 10;//单次交易的最大迭代数，无误情况下不会超过10
		private float totalAtnLoad;
		public static bool IsBetterRatio(float r1, float r2, TransType transType)
		{
			if (transType == TransType.Upgrade)
				return r1 > r2;
			return r2 > r1;
		}
		public override void Init()
		{
			if(viewCameras == null || viewCameras.Length == 0)
			{
				viewCameras = new Camera[] { Camera.main };
			}
			hypTrades = new List<SolutionTrans>();
		}
		private void Start()
		{
			upgradTrans = new MyHeap<SolutionTrans>(characters.Length);
			downgradTrans = new MyHeap<SolutionTrans>(characters.Length, true);
			upgradCharacters = new MyHeap<LOD_Character>(characters.Length, true);
			downgradCharacters = new MyHeap<LOD_Character>(characters.Length);
		}
		private void Update()
		{
			CalculateCriticalityMul(Time.deltaTime);
			RunLODTrader(ref availableResources);
		}
		public void SetCharacters(LOD_Character[] allCharacters)
		{
			characters = allCharacters;
		}
		/// <summary>
		/// 计算5种重要程度因子
		/// </summary>
		private void CalculateCriticalityMul(float deltaTime)
		{
			for(int i = 0; i < characters.Length; ++i)
			{
				characters[i].ResetCriticalityVec();
			}
			for (int j = 0; j < viewCameras.Length; ++j)
			{
				totalAtnLoad = 0;
				for (int i = 0; i < characters.Length; ++i)
				{
					characters[i].Observability.UpdateObservability(viewCameras[j]);
					characters[i].Attention.UpdateAttempAttention(viewCameras[j], characters[i].Observability.ObserValue, deltaTime);
					totalAtnLoad += characters[i].Attention.AttempAttetion;//计算总注意程度
				}
				totalAtnLoad /= 1 - ambMul; //考虑环境注意程度负载后的总注意程度
				totalAtnLoad += NEAR_ZERO; //总负载不能为0，用一个极小值兜底
				float currentAttention;
				for (int i = 0; i < characters.Length; ++i)
				{
					var observability = characters[i].Observability;
					characters[i].Attention.GetRealAttention(totalAtnLoad);
					currentAttention = characters[i].Attention.RealAttention;
					characters[i].Memory.UpdateMemory(currentAttention, totalAtnLoad, deltaTime);
					characters[i].ReturnTime.CalculateReturnTime(totalAtnLoad, observability.LastObsTime, deltaTime);
					characters[i].Duration.CalculateDuration(observability.ObserValue, currentAttention, deltaTime);
					characters[i].CalcCriticalityVec();//计算重要程度向量
				}
			}
		}
		/// <summary>
		/// 进行LOD交易，支持多种特性和多种资源
		/// </summary>
		private void RunLODTrader(ref Vector4 availableRes)
		{
			Vector4 resourceMul, hypResources;
			float totalBenefit;
			int time = 0;
			bool isOverRes = false;
			while(time < maxLoopTime && !isOverRes)
			{
				hypResources = availableRes;//复制一份虚拟资源，用以模拟交易
				totalBenefit = 0f;
				hypTrades.Clear();	
				//拟定可用升、降级交易
				resourceMul = CalcResourceMul(hypResources, TransType.Upgrade);
				var hypUpgrades = SelectTransitions( resourceMul, TransType.Upgrade, ref hypResources);
				while(!hypUpgrades.IsEmpty)
				{
					hypTrades.Add(hypUpgrades.Top);
					hypUpgrades.Top.RunTrade();
					totalBenefit += hypUpgrades.Top.BestRatio;//总效益 = 升级降低的BIR - 降级增加的BIR
					hypUpgrades.PopHeap();
				}
				isOverRes = hypResources.AnyLess(0);//是否有资源透支
				resourceMul = CalcResourceMul(hypResources, TransType.Downgrade);
				var hypDowngrades = SelectTransitions(resourceMul, TransType.Downgrade, ref hypResources);
				while(!hypDowngrades.IsEmpty)
				{
					hypTrades.Add(hypDowngrades.Top);
					hypDowngrades.Top.RunTrade();
					if(isOverRes)
						totalBenefit += hypDowngrades.Top.BestRatio;
					else
						totalBenefit -= hypDowngrades.Top.BestRatio;//总效益 = 升级降低的BIR - 降级增加的BIR
					hypDowngrades.PopHeap();
				}
				if (totalBenefit > 0)//如果总效益大于0，则实际执行这些交易
				{
					time++;
					availableRes = hypResources;
				}
				else//否则终止运行(总效益不再可能大于0)并返还特征解决方案
				{
					for(int i = 0; i < hypTrades.Count; ++i)
					{
						hypTrades[i].RecoverTrade();
					}
					return;
				}
			}
		}
		/// <summary>
		/// 计算资源因子向量
		/// </summary>
		private Vector4 CalcResourceMul(Vector4 availableRes, TransType transType)
		{
			if (availableRes == Vector4.zero) return Vector4.one;
			if(transType == TransType.Upgrade)
			{
				availableRes.x = availableRes.x == 0 ? MAX_RESOURCE : 1 / availableRes.x;
				availableRes.y = availableRes.y == 0 ? MAX_RESOURCE : 1 / availableRes.y;
				availableRes.z = availableRes.z == 0 ? MAX_RESOURCE : 1 / availableRes.z;
				availableRes.w = availableRes.w == 0 ? MAX_RESOURCE : 1 / availableRes.w; 
			}
			else
			{
				availableRes.x = availableRes.x < 0 ? -availableRes.x : 0;
				availableRes.y = availableRes.y < 0 ? -availableRes.y : 0;
				availableRes.z = availableRes.z < 0 ? -availableRes.z : 0;
				availableRes.w = availableRes.w < 0 ? -availableRes.w : 0;
			}
			return availableRes.normalized;
		}
		/// <summary>
		/// 为所有角色选择特征解决方案转化
		/// </summary>
		private MyHeap<SolutionTrans> SelectTransitions(Vector4 resourceMul, TransType transType, ref Vector4 availableRes)
		{
			var isUpgrade = transType == TransType.Upgrade;
			var tpRes = isUpgrade ? availableRes : -availableRes;
			float bestRatio = 0;
			var expansionQueue = MakeExpansionQueue(characters, transType);
			var transHeap = isUpgrade ? upgradTrans : downgradTrans;
			transHeap.Clear();
			while(!expansionQueue.IsEmpty && 
				((isUpgrade && tpRes.AllGreaterEquel(0)) || (!isUpgrade && tpRes.AnyGreater(0)) || 
				(!transHeap.IsEmpty && IsBetterRatio(expansionQueue.Top.ValueHeuristic, transHeap.Top.BestRatio, transType))))
			{
				var charct = expansionQueue.Top;
				expansionQueue.PopHeap();
				var bestTrans = charct.ExpandCharacter(transType, resourceMul, ref bestRatio);
				if(bestTrans.User != null)
				{
					bestTrans.BestRatio = bestRatio;
					transHeap.PushHeap(bestTrans);
					tpRes -= bestTrans.RelCost;
				}
				while(!transHeap.IsEmpty && 
					((isUpgrade && (tpRes + transHeap.Top.RelCost).AnyLess(0)) ||
					 !isUpgrade && (tpRes + transHeap.Top.RelCost).AllLessEquel(0)))
				{
					tpRes += transHeap.Top.RelCost;
					transHeap.PopHeap();
				}
			}
			availableRes = isUpgrade ? tpRes : -tpRes;
			return transHeap;
		}
		/// <summary>
		/// 为所有角色构建扩张队列
		/// </summary>
		private MyHeap<LOD_Character> MakeExpansionQueue(LOD_Character[] characters, TransType transType)
		{
			var expansionQueue = transType == TransType.Upgrade ? upgradCharacters : downgradCharacters;
			expansionQueue.Clear();
			for(int i = 0; i < characters.Length; ++i)
			{
				characters[i].CalcValueHeuristic(transType);
				if(characters[i].ValueHeuristic != float.MaxValue && characters[i].ValueHeuristic != float.MinValue)
					expansionQueue.PushHeap(characters[i]);
			}
			return expansionQueue;
		}
		
		#if UNITY_EDITOR
		public void UI_GetAllLODChararcters()
		{
			characters = FindObjectsOfType<LOD_Character>();
		}
		#endif
	}
}
